import mean from "./mean.js";

/**
 * [样本协方差](https://en.wikipedia.org/wiki/Sample_mean_and_covariance)计算两个数据集的协同变化程度：
 * 评估两个数据集的变动趋势是否一致。
 * x 和 y 是两个数据集，表示为数值数组。
 *
 * @param {Array<number>} x 至少包含两个数据点的样本数据
 * @param {Array<number>} y 至少包含两个数据点的样本数据
 * @throws {Error} 如果 x 和 y 的长度不相等
 * @throws {Error} 如果 x 或 y 的长度小于 2
 * @returns {number} 样本协方差
 * @example
 * sampleCovariance([1, 2, 3, 4, 5, 6], [6, 5, 4, 3, 2, 1]); // => -3.5
 */
function sampleCovariance(x, y) {
    // 两个数据集的长度必须相等，且长度必须大于 1
    if (x.length !== y.length) {
        throw new Error("sampleCovariance 需要等长的样本数据");
    }

    if (x.length < 2) {
        throw new Error("sampleCovariance 需要每个样本至少包含两个数据点");
    }

    // 计算每个数据集的均值，以便衡量每个值相对于均值的偏差。
    // 这样，当一个数据集为 [1, 2, 3]，另一个为 [2, 3, 4] 时，
    // 它们的协方差不会因为绝对数值的不同而受到影响。
    const xmean = mean(x);
    const ymean = mean(y);
    let sum = 0;

    // 对于每一对数据点，当它们相对于各自均值的偏差方向一致时，
    // 协方差增加——如果两者均高于均值或均低于均值，
    // 则协方差会显著增加。
    for (let i = 0; i < x.length; i++) {
        sum += (x[i] - xmean) * (y[i] - ymean);
    }

    // 贝塞尔校正（Bessel's Correction）：对样本统计量进行调整，
    // 以补偿由于使用样本数据而导致的自由度减少。
    const besselsCorrection = x.length - 1;

    // 计算加权协方差，归一化处理数据集的长度。
    return sum / besselsCorrection;
}

export default sampleCovariance;
